package org.jeecg.modules.flowable.controller;

import com.github.xiaoymin.knife4j.annotations.ApiSort;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.flowable.common.engine.impl.util.IoUtil;
import org.flowable.engine.*;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.DeploymentBuilder;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.repository.ProcessDefinitionQuery;
import org.jeecg.modules.flowable.common.dic.ResultMessage;
import org.jeecg.modules.flowable.common.util.tree.TreeDesc;
import org.jeecg.modules.flowable.common.util.validation.AssertValid;
import org.jeecg.modules.flowable.controller.dto.PageResult;
import org.jeecg.modules.flowable.controller.dto.ProcessDef;
import org.jeecg.modules.flowable.service.FlowableService;
import org.jeecg.modules.flowable.service.bo.TaskConfList;
import org.jeecg.modules.flowable.service.bo.taskconf.TaskConf;
import org.jeecg.modules.flowable.service.bo.taskconf.TaskConfResult;
import org.jeecg.modules.flowable.vo.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * Title:  <br>
 * Desc:  <br>
 * Date: 6/6/22 5:21 PM <br>
 * Company: 联通（辽宁）产业互联网有限公司 <br>
 *
 * @author zxd
 * @version 1.0.0
 */
@Api(value = "FlowableManagerController", tags = {"(module-flowable)-工作流管理"})
@ApiSort(value = 1)
@RestController
@RequestMapping("/FlowableManagerController")
@Slf4j
public class FlowableManagerController {

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private HistoryService historyService;

    @Autowired
    private TaskService taskService;

    @Autowired
    private IdentityService identityService;

    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private FlowableService flowableService;

//    @Value("${basicplatform.flowable.design-url}")
//    public String designUrl;

    @RequiresRoles({"admin"})
    @ApiOperation(value = "部属新流程", notes = "部属新流程")
    @RequestMapping(path = "/flowDeploy", method = RequestMethod.POST)
    @ResponseBody
    public Result<String> flowDeploy(MultipartFile f) {
        try {
            InputStream inputStream = f.getInputStream();
            String oriName = f.getOriginalFilename();
            DeploymentBuilder deploymentBuilder = repositoryService.createDeployment().addInputStream(f.getOriginalFilename(), inputStream);
            deploymentBuilder.enableDuplicateFiltering();
            deploymentBuilder.name("");
            Deployment deploy = deploymentBuilder.deploy();
            return Result.OK();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    @RequiresRoles({"admin"})
    @ApiOperation(value = "查询流程列表", notes = "查询流程列表")
    @RequestMapping(path = "/flowList", method = RequestMethod.POST)
    @ResponseBody
    public Result<PageResult<ProcessDef>> flowList(String argProcessDefId, String argProcessName, String argKey, @RequestParam("pageNo") Integer argCurrPage, @RequestParam("pageSize") Integer argPageSize) {
        // 总页数
        argCurrPage = argCurrPage - 1;
        long count = repositoryService.createProcessDefinitionQuery().latestVersion().count();
        // List<ProcessDefinition> processDefinitions = repositoryService.createProcessDefinitionQuery().latestVersion().orderByProcessDefinitionKey().asc().listPage(argCurrPage, argPageSize);
        ProcessDefinitionQuery query = repositoryService.createProcessDefinitionQuery();
        // 构建查询条件
        if (AssertValid.isNotEmpty(argProcessDefId))
            query.processDefinitionId(argProcessDefId);
        if (AssertValid.isNotEmpty(argProcessName))
            query.processDefinitionNameLike("%" + argProcessName + "%");
        if (AssertValid.isNotEmpty(argKey))
            query.processDefinitionKeyLike("%" + argKey+ "%");
        List<ProcessDefinition> processDefinitions = query.latestVersion().orderByProcessDefinitionKey().asc().listPage(argCurrPage, argPageSize);

        List<ProcessDef> collect = processDefinitions.stream().map(s -> {
            ProcessDef processDef = new ProcessDef();
            processDef.setDescription(s.getDescription());
            processDef.setId(s.getId());
            processDef.setKey(s.getKey());
            processDef.setName(s.getName());
            processDef.setSuspended(s.isSuspended());
            processDef.setVersion(s.getVersion());
            return processDef;
        }).collect(Collectors.toList());

        PageResult<ProcessDef> processDefPageResult = new PageResult<>();
        processDefPageResult.setCurrent(argCurrPage + 1).setRecords(collect).setSize(argPageSize).setTotal(count);
        return Result.OK(processDefPageResult);
    }

    @RequiresRoles({"admin"})
    @ApiOperation(value = "挂起流程", notes = "挂起流程")
    @RequestMapping(path = "/flowSsupend", method = RequestMethod.POST)
    @ResponseBody
    public Result<String> flowSsupend(String argProcessDefId) {
        repositoryService.suspendProcessDefinitionById(argProcessDefId);
        return Result.OK(ResultMessage.OK);
    }

    @RequiresRoles({"admin"})
    @ApiOperation(value = "激活流程", notes = "激活流程")
    @RequestMapping(path = "/flowActive", method = RequestMethod.POST)
    @ResponseBody
    public Result<String> flowActive(String argProcessDefId) {
        repositoryService.activateProcessDefinitionById(argProcessDefId);
        return Result.OK(ResultMessage.OK);
    }

    @ApiOperation(value = "跟据流程实例ID获得流程图", notes = "跟据流程实例ID获得流程图")
    @RequestMapping(path = "/getFlowDesignerByProcessInstanceId", method = RequestMethod.GET)
    public void getFlowDesignerByProcessInstanceId(String argProcessInstanceId, HttpServletResponse httpServletResponse) {
        InputStream in = flowableService.getFlowDesignerByProcessInstanceId(argProcessInstanceId);
        OutputStream out = null;
        byte[] buf = new byte[1024];
        int length;
        try {
            out = httpServletResponse.getOutputStream();
            while ((length = in.read(buf)) != -1) {
                out.write(buf, 0, length);
            }
        } catch (IOException e) {
            log.error("跟据流程实例ID获得流程图失败:", e);
        } finally {
            IoUtil.closeSilently(out);
            IoUtil.closeSilently(in);
        }
    }

    @ApiOperation(value = "跟据流程KEY获得流程图", notes = "跟据流程KEY获得流程图")
    @RequestMapping(path = "/getFlowDesignerByFlowKey", method = RequestMethod.GET)
    public void getFlowDesignerByFlowKey(String argKey, HttpServletResponse httpServletResponse) {
        InputStream in = flowableService.getFlowDesignerByFlowKey(argKey);
        OutputStream out = null;
        byte[] buf = new byte[1024];
        int length;
        try {
            out = httpServletResponse.getOutputStream();
            while ((length = in.read(buf)) != -1) {
                out.write(buf, 0, length);
            }
        } catch (IOException e) {
            log.error("跟据流程KEY获得流程图失败:", e);
        } finally {
            IoUtil.closeSilently(out);
            IoUtil.closeSilently(in);
        }
    }

//    @ApiOperation(value = "获得流程设计器URL地址", notes = "获得流程设计器URL地址")
//    @RequestMapping(path = "/getDesignerUrl", method = RequestMethod.POST)
//    public Result<String> getDesignerUrl() {
//        return Result.OK(designUrl);
//    }

    @RequiresRoles({"admin"})
    @ApiOperation(value = "跟据流程定义ID查询流程任务节点配置列表", notes = "跟据流程定义ID查询流程任务节点配置列表")
    @RequestMapping(path = "/getTaskConfList", method = RequestMethod.POST)
    public Result<List<TaskConfList>> getTaskConfList(String argProcessDefinitionId) {
        List<TaskConfList> taskConfList = flowableService.getTaskConfList(argProcessDefinitionId);
        return Result.OK(taskConfList);
    }

    @RequiresRoles({"admin"})
    @ApiOperation(value = "查询机构树", notes = "查询机构树")
    @RequestMapping(path = "/queryOrgTreeDesc", method = RequestMethod.POST)
    public Result<TreeDesc> queryOrgTreeDesc() {
        TreeDesc treeDesc = flowableService.queryOrgTreeDesc();
        return Result.OK(treeDesc);
    }

    @RequiresRoles({"admin"})
    @ApiOperation(value = "查询区划树", notes = "查询区划树")
    @RequestMapping(path = "/queryRegionTreeDesc", method = RequestMethod.POST)
    public Result<TreeDesc> queryRegionTreeDesc() {
        TreeDesc treeDesc = flowableService.queryRegionTreeDesc();
        return Result.OK(treeDesc);
    }

    @RequiresRoles({"admin"})
    @ApiOperation(value = "查询用户列表", notes = "查询用户列表")
    @RequestMapping(path = "/queryUserList", method = RequestMethod.POST)
    public Result<List<Map<String, Object>>> queryUserList(String argUserName) {
        List<Map<String, Object>> maps = flowableService.queryUserList(argUserName);
        return Result.OK(maps);
    }

    @RequiresRoles({"admin"})
    @ApiOperation(value = "查询角色列表", notes = "查询角色列表")
    @RequestMapping(path = "/queryRoleList", method = RequestMethod.POST)
    public Result<List<Map<String, Object>>> queryRoleList(String argRoleName) {
        List<Map<String, Object>> maps = flowableService.queryRoleList(argRoleName);
        return Result.OK(maps);
    }

    @RequiresRoles({"admin"})
    @ApiOperation(value = "保存任务配置信息", notes = "保存任务配置信息")
    @RequestMapping(path = "/saveTaskConf", method = RequestMethod.POST)
    public Result<TaskConf> saveTaskConf(@RequestBody TaskConf argTaskConf) {
        TaskConf taskConf = flowableService.saveTaskConf(argTaskConf);
        return Result.OK(taskConf);
    }

    @RequiresRoles({"admin"})
    @ApiOperation(value = "查询任务配置信息", notes = "查询任务配置信息")
    @RequestMapping(path = "/queryTaskConf", method = RequestMethod.POST)
    public Result<TaskConfResult> queryTaskConf(String taskDefKey) {
        TaskConfResult taskConfResult = flowableService.queryTaskConf(taskDefKey);
        return Result.OK(taskConfResult);
    }
}